package twobarOpt;

import inf.minife.fe.Model;
import java.io.IOException;
import data.RSData;
import randomsearch_masterworker.*;
import model.TwoBar;
import mpi.MPI;
import mpi.MPIException;

public class TwoBarOpt {
	
	final double sigmaMax_ = 25;
	final double uMax_ = 2;
	double[] x;
	
	TwoBar twobar_;
	Model model;
	
	public static void main (String[] args)
		throws MPIException, IOException{
		
		new TwoBarOpt(args);
	}	
	
	public TwoBarOpt(String[] args){
		
		int myid;
		int nprocs;
		
		/* Setup model */
		twobar_ = new TwoBar();
		model = twobar_.getModel();		
		
		/* Add master component */
		RSMaster rsmaster = new RSMaster();
		
		/* number of variables for design 
		 * H value and b1, b2 diameter of 2 bar
		 */
		
		int design_number = 3; 
		 
		/*
		 * Number of result that worker will send to master 
		 * result including: new mass value, fitness value of generation and number of
		 * violation constrains
		 */
		int result_number = 4;

		/* Number of cycles for random search */
		int number_cycles = 200;
		
		/* Initiating MPI by starting master */	
		rsmaster.startMPI(args);
		myid = rsmaster.getID();
		nprocs = rsmaster.getNumberOfProcessors();
		
		/* Set up number of workers */
		rsmaster.setNumberOfWorker(nprocs-1);
		MPI.COMM_WORLD.Barrier();
		
		/* Call master or worker code as appropriate */
		
		if (myid == 0){			

			/* Start apply model two bar */
			try{
				model.solve();
				
				/* Calculate mass value of default plane truss */
				double massvalue = model.getTotalMass();
				System.out.println("Init total mass = " + massvalue);
				callMaster(rsmaster.getNumberOfWorkers(), rsmaster, design_number, result_number, number_cycles);
			}
			catch (NullPointerException e) {
				System.out.println("Null pointer Exception for plane truss! Init it before use ");
				return;
			}
			MPI.COMM_WORLD.Barrier();
		}
		else {			
			try{
				//callWorker(myid, design_number, result_number);
				callWorker(myid, design_number, sigmaMax_, uMax_, twobar_, result_number);
			}
			catch (NullPointerException e) {
				System.out.println("Null pointer Exception for plane truss! Init it before use ");
				return;
			}
			MPI.COMM_WORLD.Barrier();
		}
		MPI.Finalize();
		
	}	
	

	/* Call Master */
	public void callMaster(int nworkers, RSMaster rsmaster,int design_number, int result_number, int number_cycles){
		
		int nmax = 100;		
		double[] a;
		int[] n = new int[nmax];
		
		//int maxiter = 0;		
		int masterID = 0;		
	
		/* Initiating arrays to store design values */		
		
		RSData[] rsdata = new RSData[design_number];
		
		
		a = rsmaster.prepareWork(n, nmax, "../SourceCode_Week7/src/randomsearch.dat");
		
		/* Pass the design value to array */
		//maxiter =(int)a[0];
		
		System.out.println("Data send from master ");
		for (int i = 0; i < design_number; i++){
			rsdata[i] = new RSData();
			
			rsdata[i].setInit(a[i+2*(i+1)]);			
			System.out.println("\n Init[" + i + "] = " + rsdata[i].getInit());
			
			rsdata[i].setLower(a[i+2*i+1]);
			System.out.println("\n Lower[" + i + "] = " + rsdata[i].getLower());
			
			rsdata[i].setUpper(a[i+2*(i+1)+1]);
			System.out.println("\n Upper[" + i + "] = " + rsdata[i].getUpper());
		}
		
		
		/* Start timing */
		rsmaster.startTime();
		
		/* Broadcast init, low, upper value */		
		MPI.COMM_WORLD.Bcast(rsdata, 0, rsdata.length, MPI.OBJECT, masterID);
		
		/* File to store result */
		String filename = "../SourceCode_Week7/src/twobar_rs_result.dat";
		
		/* Start parallel work assignment */
		rsmaster.doParallel(masterID, nworkers, result_number, number_cycles, filename);
		/* End timing */
		rsmaster.endTime();
		
		double[] starttime = rsmaster.getStarTime();
		double[] endtime = rsmaster.getEndTime();
		
		/* Print out */
		System.out.println("\n Number of workers = " + nworkers);
		
		System.out.println("\n Number of cycles = " + number_cycles);
		
		System.out.println("\n Execution MPI time = " + (endtime[0]-starttime[0]));
		System.out.println("\n Execution system time = " + (endtime[1]-starttime[1])/1000);
		
	}
	
	public void callWorker(int myid, int design_number, double sigmaMax,
			double uMax, TwoBar twobar, int result_number) {
		// TODO Auto-generated method stub
		int master = 0;
		
		/* Start worker */
		TwoBarRSWorker rsworker = new TwoBarRSWorker(myid);
		
		/* Receive initiate, lower, upper value from master */		
		RSData[] rsdata = new RSData[design_number];		
				
		MPI.COMM_WORLD.Bcast(rsdata, 0, rsdata.length, MPI.OBJECT, master);
		
		System.out.println("Data received from master ");
		for(int i = 0; i < rsdata.length; i++){
			System.out.println("Init[" + i + "] = " + rsdata[i].getInit());
			System.out.println("Upper[" + i + "] = " + rsdata[i].getLower());
			System.out.println("Lower[" + i + "] = " + rsdata[i].getUpper());
		}
		
		/* Do work */
		rsworker.doWork(myid, master, design_number, sigmaMax, uMax, twobar, result_number, rsdata);
	}
	
	
}

